package com.meida.module.arc.provider.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.meida.common.base.entity.EntityMap;
import com.meida.common.base.utils.FlymeUtils;
import com.meida.common.mybatis.base.service.impl.BaseServiceImpl;
import com.meida.common.mybatis.model.ResultBody;
import com.meida.common.mybatis.query.CriteriaDelete;
import com.meida.common.mybatis.query.CriteriaQuery;
import com.meida.common.mybatis.query.CriteriaSave;
import com.meida.common.mybatis.query.CriteriaUpdate;
import com.meida.common.utils.ApiAssert;
import com.meida.module.arc.client.constants.ArchiveConstants;
import com.meida.module.arc.client.entity.ArcCategory;
import com.meida.module.arc.client.entity.ArcInfo;
import com.meida.module.arc.client.entity.ArcStoreRoom;
import com.meida.module.arc.client.enums.ArcStoreRoomFullEnum;
import com.meida.module.arc.client.enums.ArcStoreRoomTypeEnum;
import com.meida.module.arc.client.enums.ArchiveEnumInteger;
import com.meida.module.arc.client.enums.CategoryTypeEnum;
import com.meida.module.arc.client.utils.ArcUtils;
import com.meida.module.arc.provider.mapper.ArcStoreRoomMapper;
import com.meida.module.arc.provider.service.ArcCategoryService;
import com.meida.module.arc.provider.service.ArcInfoService;
import com.meida.module.arc.provider.service.ArcStoreRoomService;
import com.meida.module.arc.provider.service.SyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * 档案库房接口实现类
 *
 * @author flyme
 * @date 2022-01-02
 */
@Service
@Transactional(rollbackFor = Exception.class)
@DS("sharding")
public class ArcStoreRoomServiceImpl extends BaseServiceImpl<ArcStoreRoomMapper, ArcStoreRoom> implements ArcStoreRoomService {

    @Autowired
    @Lazy
    private ArcInfoService arcInfoService;

    @Autowired
    private ArcCategoryService arcCategoryService;

    @Autowired
    private SyncService syncService;

    private String genSysCode(Long parentId){
        String parentSysCode = null;
        //1查询父节点sysCode
        if(!ArchiveConstants.ROOT_PARENT_ID.equals(parentId)&&FlymeUtils.isNotEmpty(parentId)){
            ArcStoreRoom room = getById(parentId);
            parentSysCode = room.getSysCode();
        }
        //2查询子节点最大sysCode
        CriteriaQuery<ArcStoreRoom> query = new CriteriaQuery<ArcStoreRoom>(ArcStoreRoom.class);
        query.lambda().eq(ArcStoreRoom::getParentId,parentId);
        query.orderByDesc("sysCode");
        query.limit(1);
        ArcStoreRoom preSysCodeObj = getOne(query);
        if(preSysCodeObj==null){
            return ArcUtils.genNextSysCode(parentSysCode,null);
        }else{
            return ArcUtils.genNextSysCode(parentSysCode,preSysCodeObj.getSysCode());
        }
    }

    @Override
    public ResultBody beforeAdd(CriteriaSave cs, ArcStoreRoom asr, EntityMap extra) {
        ApiAssert.isNotEmpty("名称不能为空",asr);
        ApiAssert.isNotEmpty("名称不能为空",asr.getName());
        ApiAssert.isNotEmpty("上级不能为空",asr.getParentId());
        ApiAssert.isNotEmpty("全宗id不能为空",asr.getQzId());
        ApiAssert.isNotEmpty("类型不能为空",asr.getType());

        if(ArchiveConstants.ROOT_PARENT_ID.equals(asr.getParentId())&&
                !ArcStoreRoomTypeEnum.ROOM_TYPE_1.getCode().equals(asr.getType())){
            ApiAssert.failure("根节点类型必须为库房");
        }
        if(!(ArchiveConstants.ROOT_PARENT_ID.equals(asr.getParentId()))){
            ArcStoreRoom parentRoom = getById(asr.getParentId());
            if((asr.getType()-parentRoom.getType())!=1){
                ApiAssert.failure("库房类型父子级错误");
            }
        }



        //获取最新的序号
        CriteriaQuery<ArcStoreRoom> query = new CriteriaQuery<ArcStoreRoom>(ArcStoreRoom.class);
        query.lambda().eq(ArcStoreRoom::getParentId,asr.getParentId());
        query.orderByDesc("seq");
        query.limit(1);
        ArcStoreRoom room = this.getOne(query);
        if(FlymeUtils.isEmpty(room)){
            asr.setSeq(0);
        }else{
            asr.setSeq(room.getSeq()+1);
        }
        asr.setIsFull(0);
        asr.setSysCode(genSysCode(asr.getParentId()));

        //级联更新已满状态
        //如果同级都为已满（等价于父级为已满） 级联向上修改为未满
        Long parentId = asr.getParentId();
        for (int i = 0; i < 3; i++) {
            ArcStoreRoom parent = getById(parentId);
            if (FlymeUtils.isNotEmpty(parent)&&ArcStoreRoomFullEnum.ROOM_FULL_2.getCode().equals(parent.getIsFull())) {
                LambdaUpdateWrapper<ArcStoreRoom> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(ArcStoreRoom::getStoreId, parentId)
                        .set(ArcStoreRoom::getIsFull, ArcStoreRoomFullEnum.ROOM_FULL_1.getCode());
                update(updateWrapper);
                parentId = parent.getParentId();
            } else {
                break;
            }
        }
        return ResultBody.ok();
    }

    /**
     * 添加或删除层
     * @param parentId
     */
    private void genFullOrNotBy4(Long parentId){

    }

    @Override
    public ResultBody beforeEdit(CriteriaUpdate<ArcStoreRoom> cu, ArcStoreRoom asr, EntityMap extra) {
        ApiAssert.isNotEmpty("编辑对象不能为空",asr);
        ApiAssert.isNotEmpty("编辑对象不能为空",asr.getStoreId());
        ApiAssert.isNotEmpty("名称不能为空",asr.getName());
        ApiAssert.isEmpty("上级不能修改",asr.getParentId());
        ApiAssert.isEmpty("类型不能修改",asr.getType());
        ArcStoreRoom room = getById(asr.getStoreId());
        ApiAssert.isNotEmpty("编辑对象不能为空",asr.getStoreId());
        if(!ArcStoreRoomTypeEnum.ROOM_TYPE_4.getCode().equals(room.getType())&&FlymeUtils.isNotEmpty(asr.getIsFull())){
            ApiAssert.failure("只有层级（第四级）可以更新是否已满状态");
        }
        if(FlymeUtils.isNotEmpty(asr.getIsFull())) {
            Integer beforeIsFull = room.getIsFull();
            Integer afterIsFull = asr.getIsFull();
            if (FlymeUtils.isNotEmpty(afterIsFull)&&!afterIsFull.equals(beforeIsFull)){
                //before 为0或1   afterIsFull为1  不处理
                if ((beforeIsFull.equals(ArcStoreRoomFullEnum.ROOM_FULL_0.getCode())
                        || beforeIsFull.equals(ArcStoreRoomFullEnum.ROOM_FULL_1.getCode()))
                        && afterIsFull.equals(ArcStoreRoomFullEnum.ROOM_FULL_1.getCode())) {

                } else {
                    if (afterIsFull.equals(ArcStoreRoomFullEnum.ROOM_FULL_1.getCode())) {
                        //从已满到未满
                        //1 当前数据更新为未满
                        //2 级联顶级更新为未满
                        Long parentId = room.getParentId();
                        for (int i = 0; i < 3; i++) {
                            ArcStoreRoom parent = getById(parentId);
                            if (FlymeUtils.isNotEmpty(parent)) {
                                LambdaUpdateWrapper<ArcStoreRoom> updateWrapper = new LambdaUpdateWrapper<>();
                                updateWrapper.eq(ArcStoreRoom::getStoreId, parentId)
                                        .set(ArcStoreRoom::getIsFull, ArcStoreRoomFullEnum.ROOM_FULL_1.getCode());
                                update(updateWrapper);
                                parentId = parent.getParentId();
                            } else {
                                break;
                            }
                        }
                    } else if (afterIsFull.equals(ArcStoreRoomFullEnum.ROOM_FULL_2.getCode())) {
                        //从 空或未满 到已满
                        //1 当前数据更新为已满
                        //2 级联向  如果同级的都为已满，则上级更新为已满
                        Long parentId = room.getParentId();
                        for (int i = 0; i < 3; i++) {
                            ArcStoreRoom parent = getById(parentId);
                            if (FlymeUtils.isNotEmpty(parent)) {
                                //查询同级是否有未满或空的
                                LambdaQueryWrapper<ArcStoreRoom> queryWrapper = new LambdaQueryWrapper<>();
                                queryWrapper.eq(ArcStoreRoom::getParentId, parentId)
                                        .in(ArcStoreRoom::getIsFull
                                                , ArcStoreRoomFullEnum.ROOM_FULL_0.getCode()
                                                , ArcStoreRoomFullEnum.ROOM_FULL_1.getCode())
                                        .ne(ArcStoreRoom::getStoreId,room.getStoreId());
                                Long count = count(queryWrapper);
                                if (FlymeUtils.isEmpty(count) || count == 0) {
                                    LambdaUpdateWrapper<ArcStoreRoom> updateWrapper = new LambdaUpdateWrapper<>();
                                    updateWrapper.eq(ArcStoreRoom::getStoreId, parentId)
                                            .set(ArcStoreRoom::getIsFull, ArcStoreRoomFullEnum.ROOM_FULL_2.getCode());
                                    update(updateWrapper);
                                    parentId = parent.getParentId();
                                } else {
                                    break;
                                }
                            } else {
                                break;
                            }
                        }
                    }
                }
            }
        }
        return ResultBody.ok();
    }

    @Override
    public ResultBody afterEdit(CriteriaUpdate cu, ArcStoreRoom t, EntityMap extra) {
        return ResultBody.ok("更新成功", t);
    }
    @Override
    public ResultBody beforeDelete(CriteriaDelete<ArcStoreRoom> cd) {
        ApiAssert.isNotEmpty("删除对象不能为空",cd.getIdValue());
        ArcStoreRoom room = getById(cd.getIdValue());
        if(room.getIsFull()==2){
            ApiAssert.failure("已满状态不能删除");
        }
        LambdaQueryWrapper<ArcCategory> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(ArcCategory::getType, CategoryTypeEnum.CATEGORY_TYPE_1,CategoryTypeEnum.CATEGORY_TYPE_4,CategoryTypeEnum.CATEGORY_TYPE_2)
                .likeRight(ArcCategory::getSysCode,"A02")
                .eq(ArcCategory::getQzId,room.getQzId());
        List<ArcCategory> categories = arcCategoryService.list(lambdaQueryWrapper);
        List<Long> categoryIds = categories.stream()
                .map(item->{
                    return item.getCategoryId();
                }).collect(Collectors.toList());
        List<Future<Long>> futures = new ArrayList<>();
        for(int i=0;i<categoryIds.size();i++){
            Future<Long> future = syncService.getCategoryHasStoreRoom(categoryIds.get(i),room.getStoreId());
            futures.add(future);
        }
        for(int i=0;i<futures.size();i++){
            try {
                Long l = futures.get(i).get();
                if(l>0){
                    return ResultBody.failed("非空状态不能删除");
                }

            } catch (Exception e) {
                log.error("删除库房异常",e);
                ApiAssert.failure("删除异常");
            }
        }
        //如果同级除了删除项，其余的都为已满   上级更新为已满
        //更新完上级 后兄弟节点都为已满  继续向上级联更新已满

        //排除id
        Long deleteId =  cd.getIdValue();
        Long parentId = room.getParentId();
        for (int i = 0; i < 3; i++) {
            ArcStoreRoom parent = getById(parentId);
            if (FlymeUtils.isNotEmpty(parent)) {
                LambdaQueryWrapper<ArcStoreRoom> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(ArcStoreRoom::getParentId, parentId)
                        .ne(ArcStoreRoom::getStoreId, deleteId)
                        .eq(ArcStoreRoom::getIsFull, ArcStoreRoomFullEnum.ROOM_FULL_2.getCode());
                long brotherFullCount = count(queryWrapper);
                LambdaQueryWrapper<ArcStoreRoom> allQueryWrapper = new LambdaQueryWrapper<>();
                allQueryWrapper.eq(ArcStoreRoom::getParentId, parentId)
                        .ne(ArcStoreRoom::getStoreId, deleteId);
                long brotherCount = count(allQueryWrapper);
                if (brotherCount == 0) {//如果删除后兄弟节点为空
                    //判断父级节点是否为已满 如果为已满更新为未满
                    if (ArcStoreRoomFullEnum.ROOM_FULL_2.getCode().equals(parent.getIsFull())) {
                        LambdaUpdateWrapper<ArcStoreRoom> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.eq(ArcStoreRoom::getStoreId, parentId)
                                .set(ArcStoreRoom::getIsFull, ArcStoreRoomFullEnum.ROOM_FULL_0.getCode());
                        update(updateWrapper);
                        parentId = parent.getParentId();
                    }
                } else {
                    if (brotherCount == brotherFullCount && !ArcStoreRoomFullEnum.ROOM_FULL_2.getCode().equals(parent.getIsFull())) {
                        LambdaUpdateWrapper<ArcStoreRoom> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.eq(ArcStoreRoom::getStoreId, parentId)
                                .set(ArcStoreRoom::getIsFull, ArcStoreRoomFullEnum.ROOM_FULL_2.getCode());
                        update(updateWrapper);
                        parentId = parent.getParentId();
                    }
                }
            } else {
                break;
            }
        }
        return ResultBody.ok();
    }

    @Override
    public ResultBody beforeListEntityMap(CriteriaQuery<ArcStoreRoom> cq, ArcStoreRoom asr, EntityMap requestMap) {
        ApiAssert.isNotEmpty("全宗id不能为空",asr);
        ApiAssert.isNotEmpty("全宗id不能为空",asr.getQzId());
        cq.lambda().eq(ArcStoreRoom::getQzId,asr.getQzId());
        cq.eq("type",asr.getType());
        cq.eq("parentId",asr.getParentId());
        return ResultBody.ok();
    }

    @Override
    public ResultBody upOrDown(Map var1) {
        ApiAssert.isNotEmpty("ID不能为空",var1.get("storeId"));
        ApiAssert.isNotEmpty("移动类型不能为空",var1.get("type"));
        //排序为从小到大排   type为1为上移  2为下移
        Long storeId = NumberUtil.parseLong(var1.get("storeId").toString());
        Integer type = NumberUtil.parseInt(var1.get("type").toString());
        if(type!=1&&type!=2){
            ApiAssert.failure("移动类型只能为上移或下移");
        }
        ArcStoreRoom room = this.getById(storeId);
        CriteriaQuery<ArcStoreRoom> query = new CriteriaQuery<ArcStoreRoom>(ArcStoreRoom.class);
        query.lambda().eq(ArcStoreRoom::getParentId,room.getParentId());//查询同级别的
        query.orderByAsc("seq");//基于seq从小到大排序
        List<ArcStoreRoom> list = this.list(query);
        int sourceIndex = -1;
        int targetIndex = -1;
        for(int i=0;i<list.size();i++){
            ArcStoreRoom obj = list.get(i);
            if(obj.getStoreId().equals(storeId)){
                if(type==1){//上移
                    if(i==0){
                        return ResultBody.failed("无法上移");
                    }else{
                        sourceIndex = i;
                        targetIndex = i-1;
                    }
                }else if(type==2){//下移
                    if(i==list.size()-1){
                        return ResultBody.failed("无法下移");
                    }else{
                        sourceIndex = i;
                        targetIndex = i+1;
                    }
                }
            }
        }
        if(sourceIndex<0||targetIndex<0){
            return ResultBody.failed("移动错误");
        }
        Long targetId = list.get(sourceIndex).getStoreId();
        list.get(sourceIndex).setStoreId(list.get(targetIndex).getStoreId());
        list.get(targetIndex).setStoreId(targetId);
        List<ArcStoreRoom> updateObj = new ArrayList<>();
        for(int i=0;i<list.size();i++){
            ArcStoreRoom obj = new ArcStoreRoom();
            obj.setStoreId(list.get(i).getStoreId());
            obj.setSeq(i);
            updateObj.add(obj);
        }
        this.saveOrUpdateBatch(updateObj);
        return ResultBody.ok();
    }

    @Override
    public String checkStoreAndChangeIsFull(Long storeId) {
        ArcStoreRoom room = getById(storeId);
        ApiAssert.isNotEmpty("没有获取到库房",room);
        if(ArcStoreRoomFullEnum.ROOM_FULL_2.getCode().equals(room.getIsFull())){
            ApiAssert.failure("该库位已满，无法再进行入库");
        }
        if(!ArcStoreRoomTypeEnum.ROOM_TYPE_4.getCode().equals(room.getType())){
            ApiAssert.failure("只能入库到层（第四级）");
        }
        StringBuffer sb = new StringBuffer();
        //当前状态为非有单未满  级联更新上级为空的  库存状态更新为有但未满
        Long parentId = room.getStoreId();
        for(int i=0;i<=3;i++){
            ArcStoreRoom parent = getById(parentId);
            if(FlymeUtils.isEmpty(parent)){
                break;
            }
            if(i==0){
                sb.insert(0,parent.getName()+"层");
            }else if(i==1){
                sb.insert(0,parent.getName()+"架-");
            }else if(i==2){
                sb.insert(0,parent.getName()+"排-");
            }else if(i==3){
                sb.insert(0,parent.getName()+"区-");
            }


            parentId = parent.getParentId();
            UpdateWrapper<ArcStoreRoom> parentUpdateObj = new UpdateWrapper<>();
            parentUpdateObj.lambda().eq(ArcStoreRoom::getStoreId,parent.getStoreId())
                    .set(ArcStoreRoom::getIsFull,ArcStoreRoomFullEnum.ROOM_FULL_1.getCode());
            this.update(parentUpdateObj);
        }
        return sb.toString();
//
//        if(!ArcStoreRoomFullEnum.ROOM_FULL_1.getCode().equals(room.getIsFull())){
//            UpdateWrapper<ArcStoreRoom> updateObj = new UpdateWrapper<>();
//            updateObj.lambda().eq(ArcStoreRoom::getStoreId,storeId)
//                    .set(ArcStoreRoom::getIsFull,ArcStoreRoomFullEnum.ROOM_FULL_1.getCode());
//            this.update(updateObj);
//            //当前状态为非有单未满  级联更新上级为空的  库存状态更新为有但未满
//            Long parentId = room.getParentId();
//            for(int i=0;i<3;i++){
//                ArcStoreRoom parent = getById(parentId);
//                if(FlymeUtils.isEmpty(parent)||!ArcStoreRoomFullEnum.ROOM_FULL_0.getCode().equals(parent.getIsFull())){
//                    break;
//                }
//                parentId = parent.getParentId();
//                UpdateWrapper<ArcStoreRoom> parentUpdateObj = new UpdateWrapper<>();
//                parentUpdateObj.lambda().eq(ArcStoreRoom::getStoreId,parent.getStoreId())
//                        .set(ArcStoreRoom::getIsFull,ArcStoreRoomFullEnum.ROOM_FULL_1.getCode());
//                this.update(parentUpdateObj);
//            }
//        }


    }

    @Override
    public ResultBody moveout(Map var1) {
        Object arcInfoIds = var1.get("arcInfoIds");
        Object categoryId = var1.get("categoryId");
        ApiAssert.isNotEmpty("档案id不能为空",arcInfoIds);
        ApiAssert.isNotEmpty("门类id不能为空",categoryId);
        String[] arcInfoIdsArr = arcInfoIds.toString().split(",");
        QueryWrapper<ArcInfo> queryWrapper = new QueryWrapper<ArcInfo>();
        queryWrapper.lambda().eq(ArcInfo::getCategoryId,Long.parseLong(categoryId.toString()))
                .in(ArcInfo::getArcInfoId, Arrays.stream(arcInfoIdsArr).map(item -> {
                        return Long.parseLong(item);
                    }).collect(Collectors.toList()));
        List<ArcInfo> arcInfoList = this.arcInfoService.list(queryWrapper);
        ApiAssert.isNotEmpty("档案信息不能为空",arcInfoList);
        StringBuffer sb = new StringBuffer();
        sb.append("移出成功");
        arcInfoList.forEach(item->{
            if(!ArchiveEnumInteger.IS_TRUE.getCode().equals(item.getIsStore())
                    ||FlymeUtils.isEmpty(item.getStoreRoomId())){
                ApiAssert.failure(String.format("档案[%s]未入库，所以无法移除",item.getMaintitle()));
            }
            Long storeId = item.getStoreRoomId();
            LambdaUpdateWrapper<ArcInfo> upadateWrapper = new LambdaUpdateWrapper<ArcInfo>();
            upadateWrapper.eq(ArcInfo::getCategoryId,item.getCategoryId())
                    .eq(ArcInfo::getArcInfoId,item.getArcInfoId())
                    .set(ArcInfo::getIsStore,ArchiveEnumInteger.IS_FALSE.getCode())
                    .set(ArcInfo::getStoreRoomId,null)
                    .set(ArcInfo::getStorageLocationName,null);
            this.arcInfoService.update(upadateWrapper);
            ArcStoreRoom store = getById(storeId);
            if(ArcStoreRoomFullEnum.ROOM_FULL_2.getCode().equals(store.getIsFull())){
                sb.append(" 仓库");
                sb.append(store.getName());
                sb.append("已满，移除后如需重新入库请手动更改库存状态");
            }
        });
        return ResultBody.msg(sb.toString());
    }


    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public ResultBody beforePageList(CriteriaQuery<ArcStoreRoom> cq, ArcStoreRoom asr, EntityMap requestMap) {
      cq.orderByDesc("asr.createTime");
      return ResultBody.ok();
    }
}
